//package com.partner.boot.service.impl;
//
//import cn.dev33.satoken.stp.StpUtil;
//import cn.hutool.core.lang.Dict;
//import cn.hutool.json.JSONUtil;
//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
//import com.fasterxml.jackson.core.JsonProcessingException;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.partner.boot.common.Constants;
//import com.partner.boot.entity.Im;
//import com.partner.boot.entity.Message;
//import com.partner.boot.entity.User;
//import com.partner.boot.service.IImService;
//import com.partner.boot.service.IMessageService;
//import com.partner.boot.service.IUserService;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.stereotype.Component;
//
//import javax.annotation.PostConstruct;
//import javax.annotation.Resource;
//import javax.websocket.*;
//import javax.websocket.server.PathParam;
//import javax.websocket.server.ServerEndpoint;
//import java.io.IOException;
//import java.time.LocalDateTime;
//import java.util.Map;
//import java.util.concurrent.ConcurrentHashMap;
//
///**
// * @author websocket服务
// */
//
//@ServerEndpoint(value = "/imserver/{id}")       // 定义路由  websocket 也需要路由
//@Component                                       // 注册为springbootservice 服务才能生效
//public class WebSocketServer {
//
//    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
//    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();  // 记录当前在线连接数
//
//    @Resource
//    IUserService userService;
//
//    @Resource
//    IImService imService;
//
//    @Resource
//    private IMessageService messageService;
//
//    private static IUserService staticUserService;
//    private static IImService staticImService;
//
//    private static IMessageService staticmessageService;
//
//
//    /**
//     * 0.页面初始化
//     * 程序初始化的时候触发这个方法  赋值
//     */
//    @PostConstruct
//    public void setStaticUser() {
//        // 在程序初始化时把 加载到内存，变成静态的成员变量
//        // 也可以通过 SpringBeanUtil ，但需要自己封装spring获取bean的类
//        staticUserService = userService;
//        staticImService = imService;
//        staticmessageService = messageService;
//    }
//
//    /**
//     * 1.页面开启
//     * 连接建立成功调用的方法 可以获取前端页面的 session (一个客户端和一个服务端建立的连接) 通过session往客户端发消息
//     * 当新的用户连接成功后，会广播给每一个用户当前有多少个人
//     * 并把新用户的 session 存到  sessionMap
//     */
//    @OnOpen
//    public void onOpen(Session session, @PathParam("id") String id) {
//        // uid 作为key：一个用户只有一个客户端，只有一个页面。
//        sessionMap.put(id, session);
//        log.info("有新用户加入，id={}, 当前在线人数为：{}", id, sessionMap.size());
//        // 将当前所有用户个数传给客户端。Dict，Hutool 提供的 字典。
//        Dict dict = Dict.create().set("nums", sessionMap.size());
//        // 后台发送消息给所有的客户端
//        sendAllMessage(JSONUtil.toJsonStr(dict));
//    }
//
//    /**
//     * 2.页面关闭
//     * 连接关闭调用的方法
//     * 刷新(session会变)，离开都算关闭
//     */
//    @OnClose
//    public void onClose(Session session, @PathParam("id") String id) {
//        // 从后台缓存去掉
//        sessionMap.remove(id);
//        log.info("有一连接关闭，id={}的用户session, 当前在线人数为：{}", id, sessionMap.size());
//        Dict dict = Dict.create().set("nums", sessionMap.size());
//        // 后台发送消息给所有的客户端
//        sendAllMessage(JSONUtil.toJsonStr(dict));
//    }
//
//    /**
//     * 3. 发送消息。核心功能。
//     * 收到客户端消息后调用的方法
//     * 后台收到客户端发送过来的消息
//     * onMessage 是一个消息的中转站
//     * 接受 浏览器端 socket.send 发送过来的 json数据
//     * @param message 客户端发送过来的消息
//     */
//    @OnMessage
//    public void onMessage(String message, Session fromSession, @PathParam("id") String id) throws JsonProcessingException {
//
//        log.info("服务端收到用户id={}的消息:{}：", id, message);
//
//        if (staticUserService == null) {
//            return;
//        }
//
//        // 查询用户
//        User user = (User) StpUtil.getSession().get(Constants.LOGIN_USER_KEY);
//        // User user =  staticUserService.getOne(new QueryWrapper<User>().eq("id", id));
//        if (user == null) {
//            log.error("获取用户信息失败，id={}", id);
//            return;
//        }
//
//        // 4
//        // 直接存到数据库里面
////        Im im = Im.builder().uid(id).username(user.getNamex()).avatar(user.getAvatar()).sign(user.getSign())
////                .createTime(LocalDateTime.now()).text(message).build();
//
//        int toid = Integer.parseInt(id);
//        Message messages = Message.builder().fromId(toid).toId(user.getId()).type(1).contents(message).time(LocalDateTime.now()).build();
//
//        // 2
//        // // 前端代码改了后 message 就不再是 json 了，而是消息字符串，需要自己构建DTO
//        // ImMessageDTO messageDTO = ImMessageDTO.builder().uid(uid).username(user.getNamex()).avatar(user.getAvatar()).sign(user.getSign())
//        //        .createTime(new Date()).text(message).build();
//
//        // 1
//        // // Json 字符串转化为数据类
//        // ImMessageDTO imMessageDTO = JSONUtil.toBean(message, ImMessageDTO.class);
//        // imMessageDTO.setCreateTime(new Date());
//
//        // 3
//        // // 存数据到数据库
//        // Im im = new Im();
//        // BeanUtil.copyProperties(messageDTO,im);
//
//
////        staticImService.save(im);
//        staticmessageService.save(messages);
//
//        // // message 处理好后再转回json；处理后的消息体；
//        // 刚发消息时显示不出来，原因：实体类加了注解@Alias("xx"),json的key会变成中文
//        // String jsonStr = JSONUtil.toJsonStr(im);
//
//        // 处理后的消息体
//        String jsonStr = new ObjectMapper().writeValueAsString(messages);
//
//        // 广播
//        // 消息体是后端构建的 前端需要使用数据时，前端自己不构建，依赖于后端发送的数据
//        // 所以自己也要接受到后端返回的消息 所以这里应该用 sendAllMessage 而不是 sendMessage
//        this.sendAllMessage(jsonStr);
//        log.info("发送消息：{}：",  jsonStr);
//    }
//
//
//
//    /**
//     * 3.1
//     * 广播 服务端发送消息给除了自己的其他客户端
//     */
//    private void sendMessage(Session fromSession, String message) {
//        sessionMap.values().forEach(session -> {
//            // 把发送消息的自己排除
//            if (fromSession != session) {
//                log.info("服务端给客户端[{}]发送消息{}：", session.getId(), message);
//                try {
//                    session.getBasicRemote().sendText(message); // 发消息
//                } catch (IOException e) {
//                    log.error("服务端发送消息给客户端异常", e);
//                }
//            }
//        });
//    }
//
//    /**
//     * 3.2
//     * 服务端发送消息给所有客户端
//     */
//    private void sendAllMessage(String message) {
//        try {
//            for (Session session : sessionMap.values()) {
//                log.info("服务端给客户端[{}]发送消息{}：", session.getId(), message);
//                session.getBasicRemote().sendText(message);
//            }
//        } catch (Exception e) {
//            log.error("服务端发送消息给客户端失败", e);
//        }
//    }
//
//
//    /**
//     * 4.
//     * 发生错误
//     */
//    @OnError
//    public void onError(Session session, Throwable error) {
//        log.error("发生错误");
//        error.printStackTrace();
//    }
//
//}
//
